#!/usr/bin/ruby

require 'optparse'

def config
  Grader::Configuration.get_instance
end

def log_file_name
  if !File.exists?(config.log_dir)
    raise "Log directory does not exist: #{config.log_dir}"
  end
  config.log_dir + 
    "/#{GRADER_ENV}.#{Process.pid}"
end

def log(str)
  if config.talkative
    puts str
  end
  if config.logging
    fp = File.open(log_file_name,"a")
    fp.puts("GRADER: #{Time.new.strftime("%H:%M")} #{str}")
    fp.close
  end
end

def parse_arguments(args)
  options = {
    :environment => 'grading',
    :problems => [],
    :submissions => []
  }
  opts = OptionParser.new do |opts|
    opts.banner = <<BANNER
grader-batch - the grader for batch grading..
Usage: grader-batch [options]
BANNER

    opts.on("-e", "--env", "Set environment: grading (*), exam, etc.") do |env|
      options[:environment] = env
    end

    opts.on("--prob p1,p2,p3", Array, "Grade problems p1, p2, and p3.") do |prob_list|
      options[:problems] += prob_list
    end
    
    opts.on("--sub s1,s2,s3", Array, "Grade submissions specified by ids") do |submission_list|
      options[:submissions] += submission_list
    end
    
    # help
    opts.on_tail("-h", "--help", "Show this message") do
      puts opts
      exit
    end
  end

  opts.parse!
  return options
end


#########################################
# main program
#########################################

options = parse_arguments(ARGV)

# reading environment and options
GRADER_ENV = options[:environment]
puts "environment: #{GRADER_ENV}"
require File.join(File.dirname(__FILE__),'config/environment')

# reading rails environment
log 'Reading rails environment'

RAILS_ENV = config.rails_env
require RAILS_ROOT + '/config/environment'

# register grader process
if config.report_grader
  grader_proc = GraderProcess.register(config.grader_hostname,
                                       Process.pid,
                                       GRADER_ENV)
else
  grader_proc = nil
end

#set loggin environment
ENV['GRADER_LOGGING'] = log_file_name

# register exit handler to report inactive, and terminated
at_exit do
  if grader_proc!=nil
    grader_proc.report_inactive 
    grader_proc.terminate
  end
end

# grading

engine = Grader::Engine.new
runner = Grader::Runner.new(engine, grader_proc)

# grade problems
options[:problems].each do |prob_name|
  grader_proc.report_active if grader_proc!=nil
  prob = Problem.find_by_name(prob_name)
  if prob==nil
    puts "cannot find problem: #{prob_name}"
  else
    runner.grade_problem(prob)
  end
  grader_proc.report_inactive if grader_proc!=nil
end

# grade submissions
options[:submissions].each do |sub_id|
  grader_proc.report_active if grader_proc!=nil
  puts "Grading #{sub_id}"
  begin
    submission = Submission.find(sub_id.to_i)
  rescue ActiveRecord::RecordNotFound
    puts "Record not found"
    submission = nil
  end

  if submission!=nil
    runner.grade_submission(submission)
  end
  grader_proc.report_inactive if grader_proc!=nil
end

puts "Done."
